/*!
redis 连接帮助模块
包括连接器
相关的操作方法
*/
use lazy_static;

use redis::{cmd, Client, Connection, RedisResult};
use std::collections::HashMap;
use std::result::Result::Ok;
use std::sync::Mutex;
lazy_static! {
    /// 定义全局的redis 配置
    ///
    /// Example:
    ///
    /// ```no_run,rust
    /// match REDIS.lock() {
    ///     Ok(mut cfg) => {
    ///         if let Some(_) = cfg.connect() {
    ///             true
    ///         } else {
    ///             false
    ///         }
    ///     }
    ///     _ => false,
    ///  }
    /// ```
    pub static ref REDIS: Mutex<RedisConfig> = Mutex::new(RedisConfig::new());
}

/// 连接定义
pub trait Connector {
    /// 获取连接客户端
    fn client(&mut self) -> Option<Client>;
    /// 获取连接
    fn connect(&mut self) -> Option<Connection>;
}

/// 连接配置对象
#[derive(Debug)]
pub struct RedisConfig {
    ///连接地址
    address: String,
    ///连接端口
    port: String,
    ///连接密码
    password: String,
    ///连接用户名
    username: String,
    ///连接数据库
    db: String,
}

impl RedisConfig {
    pub fn new() -> RedisConfig {
        RedisConfig {
            address: format!(""),
            port: format!(""),
            password: format!(""),
            username: format!(""),
            db: format!(""),
        }
    }

    pub fn set(&mut self, address: &str, port: &str, db: &str, password: &str, username: &str) {
        self.set_address(address);
        self.set_port(port);
        self.set_db(db);
        self.set_username(username);
        self.set_password(password);
    }

    pub fn set_address(&mut self, para: &str) {
        self.address = para.into();
    }

    pub fn set_port(&mut self, para: &str) {
        self.port = para.into();
    }

    pub fn set_db(&mut self, para: &str) {
        self.db = para.into();
    }

    pub fn set_username(&mut self, para: &str) {
        self.username = para.into();
    }

    pub fn set_password(&mut self, para: &str) {
        self.password = para.into();
    }

    fn parse_conn_info(&mut self) -> redis::ConnectionInfo {
        let username = if self.username == "" {
            None
        } else {
            Some((&self.username).parse().unwrap_or(String::new()))
        };
        let password = if self.password == "" {
            None
        } else {
            Some((&self.password).parse().unwrap_or(String::new()))
        };
        redis::ConnectionInfo {
            addr: redis::ConnectionAddr::Tcp(
                (&self.address).parse().unwrap_or(format!("127.0.0.1")),
                (&self.port).parse().unwrap_or(6379 as u16),
            ),
            redis: redis::RedisConnectionInfo {
                db: (&self.db).parse().unwrap_or(0),
                username,
                password,
            },
        }
    }
}

impl Connector for RedisConfig {
    fn client(&mut self) -> Option<Client> {
        match Client::open(self.parse_conn_info()) {
            Ok(client) => Some(client),
            Err(_) => None,
        }
    }
    fn connect(&mut self) -> Option<Connection> {
        match Client::open(self.parse_conn_info()) {
            Ok(client) => {
                if let Ok(conn) = client.get_connection() {
                    Some(conn)
                } else {
                    None
                }
            }
            Err(_) => None,
        }
    }
}

/// 连接redis
pub fn connect_redis(
    address: String,
    port: String,
    db: String,
    password: String,
    username: String,
) -> bool {
    match REDIS.lock() {
        Ok(mut cfg) => {
            cfg.set(&address, &port, &db, &password, &username);
            if let Some(_) = cfg.connect() {
                true
            } else {
                false
            }
        }
        _ => false,
    }
}

/// 获取db个数
pub fn get_db() -> HashMap<String, String> {
    match REDIS.lock() {
        Ok(mut r) => {
            if let Some(mut conn) = r.connect() {
                let res = cmd("config")
                    .arg("get")
                    .arg("databases")
                    .query::<HashMap<String, String>>(&mut conn);
                return match res {
                    Ok(res) => res,
                    _ => HashMap::new(),
                };
            }
            HashMap::new()
        }
        _ => HashMap::new(),
    }
}

/// 获取所有的key
pub fn get_keys(condition: &str) -> Vec<String> {
    match REDIS.lock() {
        Ok(mut r) => {
            if let Some(mut conn) = r.connect() {
                let res = cmd("keys").arg(condition).query::<Vec<String>>(&mut conn);
                return match res {
                    Ok(res) => res,
                    _ => Vec::new(),
                };
            }
            Vec::new()
        }
        _ => Vec::new(),
    }
}

/// 获取键的信息
pub fn get_infos(key: String) -> String {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res = redis::pipe()
                    .cmd("type")
                    .arg(&key)
                    .cmd("memory")
                    .arg("usage")
                    .arg(&key)
                    .cmd("pttl")
                    .arg(&key)
                    .query::<(String, i32, i32)>(&mut conn);
                return match res {
                    Ok(res) => {
                        format!("{},{},{}", res.0, res.1, res.2)
                    }
                    Err(err) => {
                        println!("null {}", err);
                        format!(",,")
                    }
                };
            } else {
                format!(",,")
            }
        }
        Err(_) => return format!(",,"),
    }
}

///删除key
pub fn delete_key(key: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                if let Ok(res) = redis::cmd("del").arg(&key).query::<bool>(&mut conn) {
                    res
                } else {
                    false
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// key是否存在
pub fn key_exist(key: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                match redis::cmd("exists").arg(&key).query::<bool>(&mut conn) {
                    Ok(res) => res,
                    Err(err) => {
                        println!("{}", err);
                        false
                    }
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// 添加string类型的key
pub fn add_string_key(key: String, value: String, time: String, time_type: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                if time.as_str() != "" {
                    match time_type.as_str() {
                        "2" => {
                            if let Ok(res) = redis::cmd("set")
                                .arg(&key)
                                .arg(&value)
                                .arg("px")
                                .arg(&time)
                                .query::<bool>(&mut conn)
                            {
                                res
                            } else {
                                false
                            }
                        }
                        _ => {
                            if let Ok(res) = redis::cmd("set")
                                .arg(&key)
                                .arg(&value)
                                .arg("ex")
                                .arg(&time)
                                .query::<bool>(&mut conn)
                            {
                                res
                            } else {
                                false
                            }
                        }
                    }
                } else {
                    match redis::cmd("set")
                        .arg(&key)
                        .arg(&value)
                        .query::<bool>(&mut conn)
                    {
                        Ok(res) => res,
                        Err(err) => {
                            println!("{}", err);
                            false
                        }
                    }
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// 重命名key
pub fn rename_key(o_key: String, n_key: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                if let Ok(res) = redis::cmd("rename")
                    .arg(&o_key)
                    .arg(&n_key)
                    .query::<bool>(&mut conn)
                {
                    res
                } else {
                    false
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// 设置key过期时间
pub fn set_key_expire(key: String, t: String, time: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                if time.as_str() == "-1" {
                    return if let Ok(res) = redis::cmd("persist").arg(&key).query::<bool>(&mut conn)
                    {
                        res
                    } else {
                        false
                    };
                }
                match t.as_str() {
                    "2" => {
                        if let Ok(res) = redis::cmd("pexpire")
                            .arg(&key)
                            .arg(&time)
                            .query::<bool>(&mut conn)
                        {
                            res
                        } else {
                            false
                        }
                    }
                    _ => {
                        if let Ok(res) = redis::cmd("expire")
                            .arg(&key)
                            .arg(&time)
                            .query::<bool>(&mut conn)
                        {
                            res
                        } else {
                            false
                        }
                    }
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// 获取string类型的数据
pub fn get_string_val(key: String) -> Option<String> {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                if let Ok(res) = redis::cmd("get").arg(&key).query::<String>(&mut conn) {
                    Some(res)
                } else {
                    None
                }
            } else {
                None
            }
        }
        Err(_) => None,
    }
}

/// 获取list类型的数据
pub fn get_list_val(
    key: String,
    page: usize,
    range: usize,
) -> RedisResult<HashMap<String, String>> {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                // 查询长度
                let len = redis::cmd("llen").arg(&key).query::<usize>(&mut conn)?;
                let max = (len as f32 / range as f32).ceil() as usize;
                let min = 1 as usize;
                let mut current_page = page;
                if page < min {
                    current_page = min;
                }
                if page > max {
                    current_page = max;
                }

                let start = (current_page - 1) * range;
                let end = current_page * range;

                let res = redis::cmd("lrange")
                    .arg(&key)
                    .arg(start)
                    .arg(end)
                    .query::<Vec<String>>(&mut conn)?;
                let mut map = HashMap::new();
                if let Ok(serialize) = serde_json::to_string(&res) {
                    map.insert("total".to_string(), format!("{}", len));
                    map.insert("list".to_string(), serialize);
                    map.insert("current".to_string(), format!("{}", current_page));
                    map.insert("size".to_string(), format!("{}", range));
                } else {
                    map.insert("total".to_string(), format!("{}", len));
                    map.insert("list".to_string(), format!("[]"));
                    map.insert("current".to_string(), format!("{}", current_page));
                    map.insert("size".to_string(), format!("{}", range));
                }
                return Ok(map);
            };
        }
        Err(_) => {}
    };
    Ok(HashMap::new())
}

/// 修改list类型的值
pub fn set_list_index_val(key: String, index: i32, value: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res = redis::cmd("lset")
                    .arg(&key)
                    .arg(index)
                    .arg(value)
                    .query::<bool>(&mut conn);
                match res {
                    Ok(_) => true,
                    Err(err) => {
                        println!("{}", err);
                        false
                    }
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// 删除list中的某一个值
pub fn delete_list_index_val(key: String, value: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                if let Ok(max) = cmd("llen").arg(&key).query::<i32>(&mut conn) {
                    if max == 1 {
                        return false;
                    }
                }
                let res = redis::cmd("lrem")
                    .arg(&key)
                    .arg("1")
                    .arg(value)
                    .query::<bool>(&mut conn);
                match res {
                    Ok(_) => true,
                    Err(err) => {
                        println!("{}", err);
                        false
                    }
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// 将一个值插入到已存在的列表
pub fn append_list_val(key: String, t: String, value: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                match t.as_str() {
                    "r" => {
                        let res = redis::cmd("rpushx")
                            .arg(&key)
                            .arg(&value)
                            .query::<bool>(&mut conn);
                        match res {
                            Ok(_) => true,
                            Err(err) => {
                                println!("redis_helper.rs line 473 err: {}", err);
                                false
                            }
                        }
                    }
                    _ => {
                        let res = redis::cmd("lpushx")
                            .arg(&key)
                            .arg(&value)
                            .query::<bool>(&mut conn);
                        match res {
                            Ok(_) => true,
                            Err(err) => {
                                println!("redis_helper.rs line 486 err: {}", err);
                                false
                            }
                        }
                    }
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// 裁剪一个list
pub fn clip_list(key: String, start: i32, end: i32) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                if start > end {
                    return false;
                }
                if let Ok(max) = cmd("llen").arg(&key).query::<i32>(&mut conn) {
                    if end > max {
                        return false;
                    }
                }
                let res = cmd("ltrim")
                    .arg(&key)
                    .arg(&start)
                    .arg(&end)
                    .query::<bool>(&mut conn);
                match res {
                    Ok(_) => true,
                    Err(err) => {
                        println!("redis_helper.rs line 514 err: {}", err);
                        false
                    }
                }
            } else {
                false
            }
        }
        Err(_) => false,
    }
}

/// 查询hash的数据
pub fn get_hash_data(key: String) -> Vec<HashMap<String, String>> {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res = redis::pipe()
                    .atomic()
                    .cmd("hkeys")
                    .arg(&key)
                    .cmd("hvals")
                    .arg(&key)
                    .query::<(Vec<String>, Vec<String>)>(&mut conn);
                match res {
                    Ok(data) => {
                        let mut i = 0;
                        let data: Vec<HashMap<String, String>> = data
                            .0
                            .iter()
                            .map(|k| {
                                let mut map = HashMap::new();
                                map.insert(format!("key"), (&k).parse().unwrap_or(format!("")));
                                map.insert(
                                    format!("value"),
                                    (&data.1.get(i).unwrap_or(&format!("")))
                                        .parse()
                                        .unwrap_or(format!("")),
                                );
                                i = i + 1;
                                return map;
                            })
                            .collect();
                        data
                    }
                    Err(err) => {
                        println!("redis_helper.rs line 562 err: {}", err);
                        vec![]
                    }
                }
            } else {
                vec![]
            }
        }
        Err(_) => vec![],
    }
}

/// 修改hash的值
pub fn edit_hash_data(key: String, field: String, value: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res = cmd("hset")
                    .arg(&key)
                    .arg(&field)
                    .arg(&value)
                    .query::<bool>(&mut conn);
                return match res {
                    Ok(_) => true,
                    Err(err) => {
                        println!("redis_helper.rs line 586 err: {}", err);
                        false
                    }
                };
            }
            false
        }
        Err(_) => false,
    }
}

/// 插入键值
pub fn append_hash_data(key: String, field: String, value: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res = cmd("hmset")
                    .arg(&key)
                    .arg(&field)
                    .arg(&value)
                    .query::<bool>(&mut conn);
                return match res {
                    Ok(_) => true,
                    Err(err) => {
                        println!("redis_helper.rs line 612 err: {}", err);
                        false
                    }
                };
            }
            false
        }
        Err(_) => false,
    }
}

///获取set数据
pub fn get_set_data(key: String) -> Vec<String> {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res = cmd("smembers").arg(&key).query::<Vec<String>>(&mut conn);
                return match res {
                    Ok(res) => res,
                    Err(err) => {
                        println!("redis_helper.rs line 641 err: {}", err);
                        vec![]
                    }
                };
            }
            vec![]
        }
        Err(_) => vec![],
    }
}

/// 添加一个set数据
pub fn append_set_val(key: String, value: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res = cmd("sadd").arg(&key).arg(&value).query::<bool>(&mut conn);
                return match res {
                    Ok(_) => true,
                    Err(err) => {
                        println!("redis_helper.rs line 641 err: {}", err);
                        false
                    }
                };
            }
            false
        }
        Err(_) => false,
    }
}

/// 删除一个值
pub fn delete_set_val(key: String, value: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res = cmd("srem").arg(&key).arg(&value).query::<bool>(&mut conn);
                return match res {
                    Ok(_) => true,
                    Err(err) => {
                        println!("redis_helper.rs line 641 err: {}", err);
                        false
                    }
                };
            }
            false
        }
        Err(_) => false,
    }
}

/// 添加list key 类型数据
pub fn add_list_key(key: String, value: String) -> bool {
    match REDIS.lock() {
        Ok(mut rdb) => {
            if let Some(mut conn) = rdb.connect() {
                let res = cmd("lpush").arg(&key).arg(&value).query::<bool>(&mut conn);
                return match res {
                    Ok(_) => true,
                    Err(err) => {
                        println!("redis_helper.rs line 710 err: {}", err);
                        false
                    }
                };
            }
            false
        }
        Err(_) => false,
    }
}
